﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using LitJson;

#if UNITY_EDITOR
using UnityEditor;
#endif

[AddComponentMenu("PUEX/EventHandle/PlaySoundHandle")]
public class PUEXPlaySoundHandle : PUEXHandle {

	#region - Editable property
	public AudioClip audioClip;
	public bool loopUntilEnd;
	public PUEXDynamicAttribute pitch;
	public PUEXDynamicAttribute pan;
	public PUEXDynamicAttribute gain;
	#endregion

	#region - Property
	protected List<AudioSource> _audioSources;
	protected AudioSource _audioSourceLooped;
	#endregion

	#region - Lifecycle
	public PUEXPlaySoundHandle ()
	{
		audioClip = null;
		loopUntilEnd = false;
		pitch = PUEXDynamicAttribute.GenerateFixed (1f);
		pan = PUEXDynamicAttribute.GenerateFixed (0f);
		gain = PUEXDynamicAttribute.GenerateFixed (1f);

		_audioSources = new List<AudioSource> ();
		_audioSourceLooped = null;
	}
	#endregion

	#region - State
	public override void pause ()
	{
		pauseSoundLooped ();
	}
	
	public override void resume ()
	{
		resumeSoundLooped ();
	}
	
	public override void stop ()
	{
		base.stop ();

		if (eventType == PUEXHandle.EvnetType.ET_EMITTER_START && loopUntilEnd == true) {
			stopSoundLooped ();
		}
	}
	#endregion

	#region - Event
	public override void notifyEmitterStart ()
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_EMITTER_START) {
			if (loopUntilEnd == true) {
				playSoundLooped ();
			} else {
				playSound ();
			}
		}
	}
	
	public override void notifyEmitterEnd ()
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_EMITTER_END) {
			playSound ();
		} else if (_enabled && eventType == PUEXHandle.EvnetType.ET_EMITTER_START && loopUntilEnd == true) {
			stopSoundLooped ();
		}
	}
	
	public override void notifyParticleEmission (PUEXParticle particle)
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_PARTICLE_EMISSION) {
			playSound ();
		}
	}
	
	public override void notifyParticleExpiration (PUEXParticle particle)
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_PARTICLE_EXPIRATION) {
			playSound ();
		}
	}
	
	public override void notifyParticleCollided (PUEXParticle particle)
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_PARTICLE_COLLIDED) {
			playSound ();
		}
	}
	
	public override void notifyEvent (string eventName)
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_NOTIFY_EVENT && this.eventName == eventName) {
			playSound ();
		}
	}
	#endregion
	
	#region - Param property
	public override void updateParams (PUEXParticleSystem system)
	{
		base.updateParams (system);

		pitch.parameterize (system);
		pan.parameterize (system);
		gain.parameterize (system);
	}
	#endregion
	
	#region - Serialization
	public override JsonData save (JsonData emitterData, JsonData systemData)
	{
		JsonData ret = base.save (emitterData, systemData);

#if UNITY_EDITOR
		string audioPath = "sound/" + Path.GetFileName(AssetDatabase.GetAssetPath (audioClip));
		ret ["audio_clip"] = audioPath;
#endif
		ret ["loop_until_end"] = loopUntilEnd;
		ret ["pitch"] = PUEXUtils.serializeDynamicAttribute (pitch);
		ret ["pan"] = PUEXUtils.serializeDynamicAttribute (pan);
		ret ["gain"] = PUEXUtils.serializeDynamicAttribute (gain);
		
		return ret;
	}
	#endregion

	#region - Sound
	protected void playSound ()
	{
		AudioSource audioSource = null;
		foreach (var existAudioSource in _audioSources) {
			if (existAudioSource.isPlaying == false) {
				audioSource = existAudioSource;
				break;
			}
		}
		if (audioSource == null) {
			audioSource = gameObject.AddComponent<AudioSource> ();
			audioSource.playOnAwake = false;
			audioSource.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor | HideFlags.HideInInspector;
			_audioSources.Add(audioSource);
		}
		
		audioSource.clip = audioClip;
		audioSource.loop = false;
		audioSource.pitch = pitch.getValue (ownerEmitter.timeFraction);
		audioSource.panStereo = pan.getValue (ownerEmitter.timeFraction);
		audioSource.volume = gain.getValue (ownerEmitter.timeFraction);
		audioSource.Play ();
	}

	protected void playSoundLooped ()
	{
		if (_audioSourceLooped == null) {
			_audioSourceLooped = gameObject.AddComponent<AudioSource> ();
			_audioSourceLooped.playOnAwake = false;

			_audioSourceLooped.clip = audioClip;
			_audioSourceLooped.loop = true;
			_audioSourceLooped.pitch = pitch.getValue (ownerEmitter.timeFraction);
			_audioSourceLooped.panStereo = pan.getValue (ownerEmitter.timeFraction);
			_audioSourceLooped.volume = gain.getValue (ownerEmitter.timeFraction);
			_audioSourceLooped.Play ();
		}
	}

	protected void stopSoundLooped ()
	{
		if (_audioSourceLooped != null) {
			_audioSourceLooped.Stop();
			_audioSourceLooped = null;
		}
	}

	protected void pauseSoundLooped ()
	{
		if (_audioSourceLooped != null) {
			_audioSourceLooped.Pause ();
		}
	}

	protected void resumeSoundLooped ()
	{
		if (_audioSourceLooped != null) {
			_audioSourceLooped.UnPause ();
		}
	}
	#endregion

}
